home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / communication / internet / amitcp3.0b / src.lha / src / amitcp / sys / mbuf.h < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-08  |  16.1 KB  |  496 lines

  1. /*
  2.  * $Id: mbuf.h,v 1.11 1993/12/18 15:28:09 jraja Exp $
  3.  *
  4.  * HISTORY
  5.  * $Log: mbuf.h,v $
  6.  * Revision 1.11  1993/12/18  15:28:09  jraja
  7.  * Made M_EOR to be defined only if USE_M_EOR is defined.
  8.  *
  9.  * Revision 1.10  1993/05/04  13:49:01  jraja
  10.  * Fixed syntax of zero length arrays with SASC.
  11.  *
  12.  * Revision 1.9  93/04/24  22:33:10  22:33:10  jraja (Jarno Tapio Rajahalme)
  13.  * Removed USECLUSTERS (now using clusters always),
  14.  * moved MSIZE from <machine/param.h> to here,
  15.  * added mbconf structure to hold configurable variables for mbufs,
  16.  * changed MCLBYTES from compile-time constant to configurable variable
  17.  * (mbconf.mclbytes), changed buffer of the mcluster to variable size,
  18.  * Added MTCOUNT, the total count of mbuf types, mbstat now has only MTCOUNT
  19.  * entries for the mbuf types,
  20.  * removed m_retryhdr() call from MGETHDR, since MGET already calls m_retry(),
  21.  * removed obsolete (memory pages) related stuff,
  22.  * moved mbuf function prototypes from distinct proto file to here.
  23.  * 
  24.  * Revision 1.8  93/04/23  02:29:43  02:29:43  ppessi (Pekka Pessi)
  25.  * Fixed type of clusterchunk
  26.  * 
  27.  * Revision 1.7  93/04/12  09:21:56  09:21:56  jraja (Jarno Tapio Rajahalme)
  28.  * Corrected MCLALLOC's comment.
  29.  * 
  30.  * Revision 1.6  93/04/06  00:09:08  00:09:08  jraja (Jarno Tapio Rajahalme)
  31.  * Changed spl function return types to spl_t.
  32.  * 
  33.  * Revision 1.5  93/04/02  01:06:50  01:06:50  jraja (Jarno Tapio Rajahalme)
  34.  * Implemented clusters.
  35.  * 
  36.  * Revision 1.4  93/03/03  19:19:31  19:19:31  jraja (Jarno Tapio Rajahalme)
  37.  * Cleanup. Moved definitions defining storage to kern/uipc_mbuf.c.
  38.  * 
  39.  * Revision 1.3  93/03/03  12:30:55  12:30:55  jraja (Jarno Tapio Rajahalme)
  40.  * Changed function prototypes to prototype file inclusion.
  41.  * 
  42.  * Revision 1.2  93/01/06  19:13:27  19:13:27  jraja (Jarno Tapio Rajahalme)
  43.  * Commented all memory clusters related stuff with #ifdef USECLUSTERS and 
  44.  * deleted some obsolete stuff.
  45.  * 
  46.  * Revision 1.1  92/11/20  15:42:12  15:42:12  jraja (Jarno Tapio Rajahalme)
  47.  * Initial revision
  48.  * 
  49.  */
  50.  
  51. /* 
  52.  * Mach Operating System
  53.  * Copyright (c) 1992 Carnegie Mellon University
  54.  * All Rights Reserved.
  55.  * 
  56.  * Permission to use, copy, modify and distribute this software and its
  57.  * documentation is hereby granted, provided that both the copyright
  58.  * notice and this permission notice appear in all copies of the
  59.  * software, derivative works or modified versions, and any portions
  60.  * thereof, and that both notices appear in supporting documentation.
  61.  * 
  62.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  63.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  64.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  65.  * 
  66.  * Carnegie Mellon requests users of this software to return to
  67.  * 
  68.  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
  69.  *  School of Computer Science
  70.  *  Carnegie Mellon University
  71.  *  Pittsburgh PA 15213-3890
  72.  * 
  73.  * any improvements or extensions that they make and grant Carnegie Mellon 
  74.  * the rights to redistribute these changes.
  75.  */
  76. /*
  77.  * HISTORY
  78.  * Log:    mbuf.h,v
  79.  * Revision 2.2  92/06/25  17:25:50  mrt
  80.  *     Return dtom back to masking.  Allocation routines will now
  81.  *     correctly allign mbufs.
  82.  *     [92/06/23            rwd]
  83.  * 
  84.  * Revision 2.1  92/04/21  17:15:34  rwd
  85.  * BSDSS
  86.  * 
  87.  *
  88.  */
  89.  
  90. /*
  91.  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
  92.  * All rights reserved.
  93.  *
  94.  * Redistribution and use in source and binary forms, with or without
  95.  * modification, are permitted provided that the following conditions
  96.  * are met:
  97.  * 1. Redistributions of source code must retain the above copyright
  98.  *    notice, this list of conditions and the following disclaimer.
  99.  * 2. Redistributions in binary form must reproduce the above copyright
  100.  *    notice, this list of conditions and the following disclaimer in the
  101.  *    documentation and/or other materials provided with the distribution.
  102.  * 3. All advertising materials mentioning features or use of this software
  103.  *    must display the following acknowledgement:
  104.  *    This product includes software developed by the University of
  105.  *    California, Berkeley and its contributors.
  106.  * 4. Neither the name of the University nor the names of its contributors
  107.  *    may be used to endorse or promote products derived from this software
  108.  *    without specific prior written permission.
  109.  *
  110.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  111.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  112.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  113.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  114.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  115.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  116.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  117.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  118.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  119.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  120.  * SUCH DAMAGE.
  121.  *
  122.  *    @(#)mbuf.h    7.14 (Berkeley) 12/5/90
  123.  */
  124.  
  125. #ifndef SYS_MBUF_H
  126. #define SYS_MBUF_H
  127.  
  128. #ifndef SYS_MALLOC_H
  129. #include <sys/malloc.h>
  130. #endif
  131.  
  132. #if 0                /* not needed (yet), DO NOT DELETE! */
  133. extern void mcl_free_routine();
  134. #endif
  135. extern struct mbuf *mfree;
  136.  
  137. /*
  138.  * Mbufs are of a single size, MSIZE, which
  139.  * includes overhead.  An mbuf may add a single "mbuf cluster" of size
  140.  * mbconf.mclbytes (see struct mbconf), which has no additional overhead
  141.  * and is used instead of the internal data area; this is done when
  142.  * at least MINCLSIZE of data must be stored.
  143.  */
  144.  
  145. #define    MSIZE        128                /* size of an mbuf */
  146. #define    MLEN        (MSIZE - sizeof(struct m_hdr))    /* normal data len */
  147. #define    MHLEN        (MLEN - sizeof(struct pkthdr))    /* data len w/pkthdr */
  148.  
  149. #define    MINCLSIZE    (MHLEN + MLEN) /* smallest amount to put in cluster */
  150. #define    M_MAXCOMPRESS    (MHLEN / 2)    /* max amount to copy for compression */
  151.  
  152. /*
  153.  * Mbuf cluster structure. The first word is used as a reference count when the
  154.  * cluster is in use and as a next pointer if on the free list.
  155.  */
  156. struct mcluster {
  157.     union {
  158.         struct mcluster *mcl_next;
  159.         short            mcl_refcnt;    /* reference count */
  160.     } mcl;
  161.     char    mcl_buf[0];    /* variable size (mbconf.mclbytes) */
  162. };
  163.  
  164. /*
  165.  * Macros for type conversion
  166.  * mtod(m,t) -    convert mbuf pointer to data pointer of correct type
  167.  * dtom(x) -    convert data pointer within mbuf to mbuf pointer (XXX)
  168.  *              WARNING: cannot be used with clusters
  169.  */
  170. #define mtod(m,t)    ((t)((m)->m_data))
  171. #define    dtom(x)        ((struct mbuf *)((int)(x) & ~(MSIZE-1)))
  172.  
  173. /* header at beginning of each mbuf: */
  174. struct m_hdr {
  175.     struct    mbuf *mh_next;        /* next buffer in chain */
  176.     struct    mbuf *mh_nextpkt;    /* next chain in queue/record */
  177.     int    mh_len;            /* amount of data in this mbuf */
  178.     caddr_t    mh_data;        /* location of data */
  179.     short    mh_type;        /* type of data in this mbuf */
  180.     short    mh_flags;        /* flags; see below */
  181. };
  182.  
  183. /* record/packet header in first mbuf of chain; valid if M_PKTHDR set */
  184. struct    pkthdr {
  185.     int    len;        /* total packet length */
  186.     struct    ifnet *rcvif;    /* rcv interface */
  187. };
  188.  
  189. /* description of external storage mapped into mbuf, valid if M_EXT set */
  190. struct m_ext {
  191.     struct mcluster *ext_buf;    /* external buffer */
  192. #if 0                    /* Not used in AmiTCP/IP */
  193.     void    (*ext_free)();        /* free routine if not the usual */
  194. #endif
  195.     u_int    ext_size;        /* size of buffer, for ext_free */
  196. };
  197.  
  198. struct mbuf {
  199.     struct    m_hdr m_hdr;
  200.     union {
  201.         struct {
  202.             struct    pkthdr MH_pkthdr;    /* M_PKTHDR set */
  203.             union {
  204.                 struct    m_ext MH_ext;    /* M_EXT set */
  205.                 char    MH_databuf[MHLEN];
  206.             } MH_dat;
  207.         } MH;
  208.         char    M_databuf[MLEN];        /* !M_PKTHDR, !M_EXT */
  209.     } M_dat;
  210. };
  211. #define    m_next        m_hdr.mh_next
  212. #define    m_len        m_hdr.mh_len
  213. #define    m_data        m_hdr.mh_data
  214. #define    m_type        m_hdr.mh_type
  215. #define    m_flags        m_hdr.mh_flags
  216. #define    m_nextpkt    m_hdr.mh_nextpkt
  217. #define    m_act        m_nextpkt
  218. #define    m_pkthdr    M_dat.MH.MH_pkthdr
  219. #define    m_ext        M_dat.MH.MH_dat.MH_ext
  220. #define    m_pktdat    M_dat.MH.MH_dat.MH_databuf
  221. #define    m_dat        M_dat.M_databuf
  222.  
  223. /* mbuf flags */
  224. /*
  225.  * The M_EOR flag is not used by the TCP/IP protocols, so it is left
  226.  * undefined, unless you define USE_M_EOR.
  227.  */
  228. #define    M_EXT        0x0001    /* has associated external storage */
  229. #define    M_PKTHDR    0x0002    /* start of record */
  230. #ifdef USE_M_EOR
  231. #define    M_EOR        0x0004    /* end of record */
  232. #endif
  233. /* mbuf pkthdr flags, also in m_flags */
  234. #define    M_BCAST        0x0100    /* send/received as link-level broadcast */
  235. #define    M_MCAST        0x0200    /* send/received as link-level multicast */
  236.  
  237. /* flags copied when copying m_pkthdr */
  238. #ifdef USE_M_EOR
  239. #define    M_COPYFLAGS    (M_PKTHDR|M_EOR|M_BCAST|M_MCAST)
  240. #else
  241. #define    M_COPYFLAGS    (M_PKTHDR|M_BCAST|M_MCAST)
  242. #endif
  243.  
  244.  
  245. /* mbuf types */
  246. #define    MT_FREE        0    /* should be on free list */
  247. #define    MT_DATA        1    /* dynamic (data) allocation */
  248. #define    MT_HEADER    2    /* packet header */
  249. #define    MT_SOCKET    3    /* socket structure */
  250. #define    MT_PCB        4    /* protocol control block */
  251. #define    MT_RTABLE    5    /* routing tables */
  252. #define    MT_HTABLE    6    /* IMP host tables */
  253. #define    MT_ATABLE    7    /* address resolution tables */
  254. #define    MT_SONAME    8    /* socket name */
  255. #define    MT_SOOPTS    10    /* socket options */
  256. #define    MT_FTABLE    11    /* fragment reassembly header */
  257. #define    MT_RIGHTS    12    /* access rights */
  258. #define    MT_IFADDR    13    /* interface address */
  259. #define MT_CONTROL    14    /* extra-data protocol message */
  260. #define MT_OOBDATA    15    /* expedited data  */
  261. #define MTCOUNT         16    /* TOTAL COUNT OF THE TYPES */
  262.  
  263. /* flags to m_get/MGET */
  264. #define    M_DONTWAIT    M_NOWAIT
  265. #define    M_WAIT        M_WAITOK
  266.  
  267. /*
  268.  * mbuf allocation/deallocation macros:
  269.  *
  270.  *    MGET(struct mbuf *m, int canwait, int type)
  271.  * allocates an mbuf and initializes it to contain internal data.
  272.  *
  273.  *    MGETHDR(struct mbuf *m, int canwait, int type)
  274.  * allocates an mbuf and initializes it to contain a packet header
  275.  * and internal data.
  276.  */
  277. #define    MGET(m, canwait, type) { \
  278.     spl_t ms = splimp(); \
  279.         (m) = mfree; \
  280.     if (m) { \
  281.         mfree = (m)->m_next; \
  282.         (m)->m_type = (type); \
  283.         mbstat.m_mtypes[type]++; \
  284.         (m)->m_next = NULL; \
  285.         (m)->m_nextpkt = NULL; \
  286.         (m)->m_data = (m)->m_dat; \
  287.         (m)->m_flags = 0; \
  288.     } else \
  289.         (m) = m_retry((canwait), (type)); \
  290.     splx(ms); \
  291. }
  292.  
  293. #define    MGETHDR(m, canwait, type) { \
  294.     MGET(m, canwait, type) \
  295.     if (m) { \
  296.             (m)->m_data = (m)->m_pktdat; \
  297.             (m)->m_flags = M_PKTHDR; \
  298.     } \
  299. }
  300.  
  301. /*
  302.  * Mbuf cluster macros.
  303.  * MCLALLOC(struct mcluster *p, int canwait) allocates an mbuf cluster.
  304.  * MCLGET adds such clusters to a normal mbuf;
  305.  * the flag M_EXT is set upon success.
  306.  * MCLFREE releases a reference to a cluster allocated by MCLALLOC,
  307.  * freeing the cluster if the reference count has reached 0.
  308.  */
  309.  
  310. #define    MCLALLOC(p, canwait) \
  311.     { spl_t ms = splimp(); \
  312.       if (mclfree == 0) \
  313.         (void)m_clalloc(mbconf.clusterchunk, (canwait)); \
  314.       if ((p) = mclfree) { \
  315.         mbstat.m_clfree--; \
  316.         mclfree = (p)->mcl.mcl_next; \
  317.         (p)->mcl.mcl_refcnt = 1; \
  318.       } \
  319.       splx(ms); \
  320.     }
  321.  
  322. #define    MCLGET(m, canwait) \
  323.     { MCLALLOC((m)->m_ext.ext_buf, (canwait)); \
  324.       if ((m)->m_ext.ext_buf != NULL) { \
  325.         (m)->m_data = (m)->m_ext.ext_buf->mcl_buf; \
  326.         (m)->m_flags |= M_EXT; \
  327.         (m)->m_ext.ext_size = mbconf.mclbytes; \
  328. /*            (m)->m_ext.ext_free = mcl_free_routine; */ \
  329.       } \
  330.     }
  331.  
  332. #define    MCLFREE(p) \
  333.     { spl_t ms = splimp(); \
  334.       if (--((p)->mcl.mcl_refcnt) == 0) { \
  335.         (p)->mcl.mcl_next = mclfree; \
  336.         mclfree = (p); \
  337.         mbstat.m_clfree++; \
  338.       } \
  339.       splx(ms); \
  340.     }
  341.  
  342. /*
  343.  * MFREE(struct mbuf *m, struct mbuf *n)
  344.  * Free a single mbuf and associated external storage.
  345.  * Place the successor, if any, in n.
  346.  */
  347. #define    MFREE(m, n) \
  348.     { spl_t ms = splimp(); \
  349.       mbstat.m_mtypes[(m)->m_type]--; \
  350.       if ((m)->m_flags & M_EXT) { \
  351. /*        if ((m)->m_ext.ext_free) */ \
  352. /*            (*((m)->m_ext.ext_free))((m)->m_ext.ext_buf, */ \
  353. /*                (m)->m_ext.ext_size); */ \
  354. /*        else */ \
  355.             MCLFREE((m)->m_ext.ext_buf); \
  356.       } \
  357.       (n) = (m)->m_next; \
  358.       (m)->m_next = mfree; mfree = (m); \
  359.       splx(ms); \
  360.     }
  361.  
  362. /*
  363.  * Copy mbuf pkthdr from from to to.
  364.  * from must have M_PKTHDR set, and to must be empty.
  365.  */
  366. #define    M_COPY_PKTHDR(to, from) { \
  367.     (to)->m_pkthdr = (from)->m_pkthdr; \
  368.     (to)->m_flags = (from)->m_flags & M_COPYFLAGS; \
  369.     (to)->m_data = (to)->m_pktdat; \
  370. }
  371.  
  372. /*
  373.  * Set the m_data pointer of a newly-allocated mbuf (m_get/MGET) to place
  374.  * an object of the specified size at the end of the mbuf, longword aligned.
  375.  */
  376. #define    M_ALIGN(m, len) \
  377.     { (m)->m_data += (MLEN - (len)) &~ (sizeof(long) - 1); }
  378. /*
  379.  * As above, for mbufs allocated with m_gethdr/MGETHDR
  380.  * or initialized by M_COPY_PKTHDR.
  381.  */
  382. #define    MH_ALIGN(m, len) \
  383.     { (m)->m_data += (MHLEN - (len)) &~ (sizeof(long) - 1); }
  384.  
  385. /*
  386.  * Compute the amount of space available
  387.  * before the current start of data in an mbuf.
  388.  */
  389. #define    M_LEADINGSPACE(m) \
  390.         ((m)->m_flags & M_EXT ? /* (m)->m_data - (m)->m_ext.ext_buf */ 0 : \
  391.         (m)->m_flags & M_PKTHDR ? (m)->m_data - (m)->m_pktdat : \
  392.         (m)->m_data - (m)->m_dat)
  393.  
  394. /*
  395.  * Compute the amount of space available
  396.  * after the end of data in an mbuf.
  397.  */
  398. #define    M_TRAILINGSPACE(m) \
  399.     ((m)->m_flags & M_EXT ? (m)->m_ext.ext_buf->mcl_buf + (m)->m_ext.ext_size - \
  400.         ((m)->m_data + (m)->m_len) : \
  401.         &(m)->m_dat[MLEN] - ((m)->m_data + (m)->m_len))
  402.  
  403. /*
  404.  * Arrange to prepend space of size plen to mbuf m.
  405.  * If a new mbuf must be allocated, canwait specifies whether to wait.
  406.  * If canwait is M_DONTWAIT and allocation fails, the original mbuf chain
  407.  * is freed and m is set to NULL.
  408.  */
  409. #define    M_PREPEND(m, plen, canwait) { \
  410.     if (M_LEADINGSPACE(m) >= (plen)) { \
  411.         (m)->m_data -= (plen); \
  412.         (m)->m_len += (plen); \
  413.     } else \
  414.         (m) = m_prepend((m), (plen), (canwait)); \
  415.     if ((m) && (m)->m_flags & M_PKTHDR) \
  416.         (m)->m_pkthdr.len += (plen); \
  417. }
  418.  
  419. /* change mbuf to new type */
  420. #define MCHTYPE(m, t) { \
  421.     mbstat.m_mtypes[(m)->m_type]--; \
  422.     mbstat.m_mtypes[t]++; \
  423.     (m)->m_type = t;\
  424. }
  425.  
  426. /* length to m_copy to copy all */
  427. #define    M_COPYALL    1000000000
  428.  
  429. /* compatiblity with 4.3 */
  430. #define  m_copy(m, o, l)    m_copym((m), (o), (l), M_DONTWAIT)
  431.  
  432. /*
  433.  * Configurable variables. These are put in a structure to ensure that they
  434.  * will be in sequence, since these are accessed as an array of u_longs
  435.  * from the <kern/amiga_config.c>.
  436.  * NOTE: <kern/amiga_config.c> depends on the order of these values.
  437.  */
  438. struct mbconf {
  439.   u_long initial_mbuf_chunks;   /* # of mbuf chunks to allocate initially */
  440.   u_long mbufchunk;         /* # of mbufs to allocate at a time */
  441.   u_long clusterchunk;        /* # of clusters to allocate at a time */
  442.   u_long maxmem;        /* maximum memory to use (in kilobytes) */
  443.   u_long mclbytes;        /* size of the mbuf cluster */
  444. };
  445.  
  446. /*
  447.  * Mbuf statistics.
  448.  */
  449. struct mbstat {
  450.     u_long    m_mbufs;    /* mbufs obtained from page pool */
  451.     u_long    m_clusters;    /* clusters obtained from page pool */
  452.     u_long    m_clfree;    /* free clusters */
  453.     u_long    m_drops;    /* times failed to find space */
  454.     u_long    m_wait;        /* times waited for space */
  455.     u_long    m_drain;    /* times drained protocols for space */
  456.     u_long  m_memused;    /* total amount of memory used for mbufs */
  457.     u_short    m_mtypes[MTCOUNT];    /* type specific mbuf allocations */
  458. };
  459.  
  460. #ifdef    KERNEL
  461. /*
  462.  * changed definitions to external declarations, storege is now defined
  463.  * in kern/uipc_mbuf.c
  464.  */
  465. extern struct mcluster *mclfree;
  466. extern struct mbconf   mbconf;
  467. extern struct mbstat   mbstat;
  468. extern int             max_linkhdr;    /* largest link-level header */
  469. extern int             max_protohdr;    /* largest protocol header */
  470. extern int             max_hdr;        /* largest link+protocol header */
  471. extern int             max_datalen;    /* MHLEN - max_hdr */
  472.  
  473. int mb_check_conf(void *dp, LONG newvalue);
  474.  
  475. BOOL mbinit(void);
  476. void mbdeinit(void);
  477. BOOL m_alloc(int howmany, int canwait);
  478. BOOL m_clalloc(int ncl, int canwait);
  479. struct mbuf * m_retry(int canwait, int type);
  480. void m_reclaim(void);
  481. struct mbuf * m_get(int canwait, int type);
  482. struct mbuf * m_gethdr(int canwait, int type);
  483. struct mbuf * m_getclr(int canwait, int type);
  484. struct mbuf * m_free(struct mbuf * m);
  485. void m_freem(struct mbuf * m);
  486. struct mbuf * m_prepend(struct mbuf * m, int len, int canwait);
  487. struct mbuf * m_copym(struct mbuf * m, int off0, int len, int wait);
  488. void m_copydata(struct mbuf * m, int off, int len, caddr_t cp);
  489. void m_cat(struct mbuf * m, struct mbuf * n);
  490. void m_adj(struct mbuf * mp, int req_len);
  491. struct mbuf * m_pullup(struct mbuf * n, int len);
  492.  
  493. #endif /* KERNEL */
  494.  
  495. #endif /* !SYS_MBUF_H */
  496.